#include "StatusGrpcClient.h"
#include "configMgr.h"
#include "RedisMgr.h"

StatusConPool::StatusConPool(size_t poolsize, std::string host, std::string port):_poolsize(poolsize),_port(port),_host(host),_b_stop(false)
{
	for (size_t i = 0;i < poolsize;++i)
	{
		std::shared_ptr<grpc::Channel>	channel = grpc::CreateChannel(host + ":" + port, grpc::InsecureChannelCredentials());
		_stubs.emplace(message::StatusService::NewStub(channel));
	}
}

StatusConPool::~StatusConPool()
{
	std::lock_guard<std::mutex> lock(_mtx);
	Close();
	while (!_stubs.empty())
	{
		_stubs.pop();
	}
}

std::unique_ptr<message::StatusService::Stub> StatusConPool::getStub()
{
	std::unique_lock<std::mutex> lock(_mtx);
	_condvar.wait(lock, [this]() {
		if (_b_stop)
			return true;
		return !_stubs.empty();
		});
	if (_b_stop)
	{
		return nullptr;
	}
	auto stub = std::move(_stubs.front());
	_stubs.pop();
	return stub;
}

void StatusConPool::returnStub(std::unique_ptr<message::StatusService::Stub> con)
{
	std::unique_lock<std::mutex> lock(_mtx);
	if (_b_stop)
	{
		return;
	}
	_stubs.push(std::move(con));
	_condvar.notify_one();
}

void StatusConPool::Close()
{
	_b_stop = true;
	_condvar.notify_all();
}

StatusGrpcClient& StatusGrpcClient::GetInst()
{
	static StatusGrpcClient instance;
	return instance;
}

message::GetChatServerRsp StatusGrpcClient::GetChatServer(int uid)
{ 
	grpc::ClientContext context;
	message::GetChatServerRsp reply;
	message::GetChatServerReq request;
	request.set_uid(uid);
	auto stub = _pool->getStub();
	grpc::Status  status= stub->GetChatServer(&context, request, &reply);
	Defer defer([this,&stub]() {
		_pool->returnStub(std::move(stub));
		});
	if (status.ok())
	{
		return reply;
	}
	else
	{
		reply.set_error(ErrorCodes::RPCFailed);
		return reply;
	}
}

message::LoginRsp StatusGrpcClient::Login(int uid, std::string token)
{
	grpc::ClientContext context;
	message::LoginReq request;
	message::LoginRsp reply;
	request.set_uid(uid);
	request.set_token(token);
	auto stub = _pool->getStub();
	grpc::Status status = stub->Login(&context,request,&reply);
	Defer defer([this, &stub]() {
		_pool->returnStub(std::move(stub));
		});
	if (status.ok())
	{
		return reply;
	}
	else
	{
		reply.set_error(ErrorCodes::RPCFailed);
		return reply;
	}
}

StatusGrpcClient::~StatusGrpcClient()
{
}
StatusGrpcClient::StatusGrpcClient()
{
	auto& config = configMgr::GetInst();
	auto host = config["StatusServer"]["host"];
	auto port = config["StatusServer"]["port"];
	_pool.reset(new StatusConPool(5, host, port));
}